// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package checks

import (
	"os/exec"
	"time"

	"github.com/didi/nightingale/src/common/dataobj"
	"github.com/didi/nightingale/src/models"
	"github.com/didi/nightingale/src/modules/agent/config"
	"github.com/didi/nightingale/src/modules/agent/ecache"
	"github.com/didi/nightingale/src/modules/agent/report"
	"github.com/didi/nightingale/src/modules/agent/stra"
	gcron "github.com/robfig/cron/v3"
	"github.com/toolkits/pkg/logger"
)

type CheckScheduler struct {
	Cron  *gcron.Cron
	Check *models.CheckCollect
	Quit  chan struct{}
}

func NewCheckScheduler(check *models.CheckCollect) *CheckScheduler {
	scheduler := CheckScheduler{Check: check}
	scheduler.Cron = gcron.New() //自定义解析器
	scheduler.Quit = make(chan struct{})
	return &scheduler
}

func (c *CheckScheduler) Schedule() {
	go func() {
		_, err := c.Cron.AddFunc(c.Check.Cron, func() { //注意，这里，跟秒级别有差别
			CheckRun(c.Check)
		})
		if err != nil {
			logger.Errorf("add check cron job err:%v, job:%v", err, c.Check)
		}
		go c.Cron.Start()
		for {
			select {
			case <-c.Quit:
				c.Cron.Stop()
				return
			}
		}
	}()
}

func (c *CheckScheduler) Stop() {
	close(c.Quit)
}

func CheckRun(check *models.CheckCollect) {
	if check.Comment == "" {
		logger.Error("check commnet is not null")
		return
	}
	logger.Infof("check %v id :%v 开始执行: %+v", check.Ctype, check.Id, check)
	cmd := exec.Command("bash", "-c", check.Comment)

	checkinfo := dataobj.CheckInfo{
		Checkid:   check.Id,
		Name:      check.Name,
		Checktime: time.Now().Format("2006-01-02 15:04:05"),
	}
	output, err := cmd.CombinedOutput()

	if err != nil {
		checkinfo.Checkstatus = false
	} else {
		checkinfo.Checkstatus = true
	}
	checkinfo.Output = string(output)
	envType := "general"
	if check.Ctype == "init" {
		envType = "general"
	} else if check.Ctype == "custom" {
		envType = "personal"
	} else {
		logger.Error("check Ctype is not init or custom")
		return
	}
	recvEnvValues := map[string]interface{}{
		"hostname": config.Endpoint,
		"envtype":  envType,
		"node":     stra.Collect.Node,
		"doc":      checkinfo,
		"labels":   ecache.LabelCache.GetAll(),
	}
	err = report.ReportTransferData(recvEnvValues, true)
	if err != nil {
		logger.Errorf("checkinfo %+v upload error, err: %+v", recvEnvValues, err)
	}
}
